<?php

class Verify {
    private $seKey='ThisCommonVerifyClass';
    private $charset = 'abcdefghkmnprstuvwxyzABCDEFGHKMNPRSTUVWXYZ23456789'; //随机因子
    private $code;       //验证码
    private $codelen = 4;     //验证码长度
    private $width = 130;     //宽度
    private $height = 50;     //高度
    private $img;        //图形资源句柄
    private $font;        //指定的字体
    private $fontsize = 20;    //指定字体大小
    private $fontcolor;      //指定字体颜色  
    private $expire=1800;  //验证码过期时间
    private $reset=true;

    //构造方法初始化

    public function __construct($width=130,$height = 50,$codelen = 4,$fontsize = 20,$reset=true) {
        $this->width=$width;
        $this->height=$height;
        $this->codelen=$codelen;
        $this->fontsize=$fontsize;
        $this->reset=$reset;
        
        $this->font = __DIR__. '/font/'.  rand(1, 6).'.ttf';
        session_start();  
    }

    //生成随机码
    private function createCode($id='') {
        $_len = strlen($this->charset) - 1;
        for ($i = 0; $i < $this->codelen; $i++) {
            $this->code .= $this->charset[mt_rand(0, $_len)];
        }
        $secode     =   array();
        $code       =   $this->authcode(strtoupper($this->code));
        $secode['verify_code'] = $code; // 把校验码保存到session
        $secode['verify_time'] = time();  // 验证码创建时间
        $key        =   $this->authcode($this->seKey);
        $_SESSION[$key.$id]=$secode;
    }

    //生成背景
    private function createBg() {
        $this->img = imagecreatetruecolor($this->width, $this->height);
        $color = imagecolorallocate($this->img, mt_rand(157, 255), mt_rand(157, 255), mt_rand(157, 255));
        imagefilledrectangle($this->img, 0, $this->height, $this->width, 0, $color);
    }

    //生成文字
    private function createFont() {
        $_x = $this->width / $this->codelen;
        for ($i = 0; $i < $this->codelen; $i++) {
            $this->fontcolor = imagecolorallocate($this->img, mt_rand(0, 156), mt_rand(0, 156), mt_rand(0, 156));
            imagettftext($this->img, $this->fontsize, mt_rand(-30, 30), $_x * $i + mt_rand(1, 5), $this->height / 1.4, $this->fontcolor, $this->font, $this->code[$i]);
        }
    }

    //生成线条、雪花
    private function createLine() {
        for ($i = 0; $i < 6; $i++) {
            $color = imagecolorallocate($this->img, mt_rand(0, 156), mt_rand(0, 156), mt_rand(0, 156));
            imageline($this->img, mt_rand(0, $this->width), mt_rand(0, $this->height), mt_rand(0, $this->width), mt_rand(0, $this->height), $color);
        }
        for ($i = 0; $i < 100; $i++) {
            $color = imagecolorallocate($this->img, mt_rand(200, 255), mt_rand(200, 255), mt_rand(200, 255));
            imagestring($this->img, mt_rand(1, 5), mt_rand(0, $this->width), mt_rand(0, $this->height), '*', $color);
        }
    }

    //输出
    private function outPut() {
        header('Content-type:image/png');
        imagepng($this->img);
        imagedestroy($this->img);
    }

    //对外生成
    public function doimg($id='') {
        $this->createBg();
        $this->createCode($id);
        $this->createLine();
        $this->createFont();
        $this->outPut();
    }

    //获取验证码
    public function getCode() {
        return strtolower($this->code);
    }

    /**
     * 验证验证的正确性
     * @param type $code 验证码
     * @param type $id 自定义的id ，与生成验证码保持一致
     * @return boolean 验证结果
     */
    public function check($code, $id = '') {
        $key = $this->authcode($this->seKey).$id;
        $secode = $_SESSION[$key];
        
        if(empty($code) || empty($secode)) {
            return false;
        }
        // session 过期
        if(time() - $secode['verify_time'] > $this->expire) {
            $_SESSION[$key]= null;
            return false;
        }

        if($this->authcode(strtoupper($code)) == $secode['verify_code']) {
            $this->reset && $_SESSION[$key]= null;
            return true;
        }
        return false;
    }
    
     /* 加密验证码 */
    private function authcode($str){
        $key = substr(md5($this->seKey), 5, 8);
        $str = substr(md5($str), 8, 10);
        return md5($key . $str);
    }
}
